import React, { createContext, useContext, useEffect, useState, useRef, useCallback } from 'react';
import type { MessageInstance } from 'antd/es/message/interface';

// 定义设备和日志的数据结构，与后端和组件保持一致
export interface Device {
    id: string;
    device_id: string;
    name: string;
    location: string;
    status: 'online' | 'offline' | 'error';
    last_seen: string;
    ip_address: string;
    firmware_version: string;
    created_at: string;
    camera_service_name: string | null;
}

export interface AccessLog {
    id: number;
    user: string;
    device: string;
    device_id: string;
    timestamp: string;
    is_success: boolean;
    snapshot_path: string;
    user_avatar: string | null;
}

// 定义Context中共享的数据和方法
interface WebSocketContextType {
    devices: Device[];
    logs: AccessLog[];
    isConnected: boolean;
    error: string | null;
    removeLogById: (logId: number) => void;
}

// 创建Context
const WebSocketContext = createContext<WebSocketContextType | undefined>(undefined);

// 创建一个自定义Hook，方便子组件使用Context
export const useWebSocket = () => {
    const context = useContext(WebSocketContext);
    if (!context) {
        throw new Error('useWebSocket must be used within a WebSocketProvider');
    }
    return context;
};

// WebSocket Provider组件
interface WebSocketProviderProps {
    children: React.ReactNode;
    messageApi: MessageInstance;
}

export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({ children, messageApi }) => {
    const [devices, setDevices] = useState<Device[]>([]);
    const [logs, setLogs] = useState<AccessLog[]>([]);
    const [isConnected, setIsConnected] = useState(false);
    const [error, setError] = useState<string | null>(null);
    const socketRef = useRef<WebSocket | null>(null);

    const connect = useCallback(() => {
        const token = localStorage.getItem('adminAuthToken');
        if (!token) {
            console.error("WebSocket: No admin token found.");
            setError("Admin token not found. Cannot connect to WebSocket.");
            return;
        }

        // 根据环境确定协议
        const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
        const wsUrl = `${protocol}//${window.location.host}/ws/admin/monitor/?token=${token}`;

        console.log("WebSocket: Attempting to connect to", wsUrl);

        const socket = new WebSocket(wsUrl);
        socketRef.current = socket;

        socket.onopen = () => {
            console.log("WebSocket: Connection established.");
            setIsConnected(true);
            setError(null);
            messageApi.success('已连接到实时监控服务', 2);
        };

        socket.onmessage = (event) => {
            const data = JSON.parse(event.data);
            console.log("WebSocket: Received message:", data);

            switch (data.type) {
                case 'initial_device_list':
                    // 用后端发来的完整列表替换当前设备列表
                    setDevices(data.payload);
                    break;
                case 'initial_log_list':
                    // 用后端发来的完整列表替换当前日志列表
                    setLogs(data.payload);
                    break;
                case 'device_status_update':
                    // 处理单个设备的实时更新
                    setDevices(prevDevices => {
                        const existingDeviceIndex = prevDevices.findIndex(d => d.device_id === data.payload.device_id);
                        if (existingDeviceIndex > -1) {
                            // 更新现有设备
                            const updatedDevices = [...prevDevices];
                            updatedDevices[existingDeviceIndex] = data.payload;
                            return updatedDevices;
                        } else {
                            // 添加新设备
                            return [...prevDevices, data.payload];
                        }
                    });
                    break;
                case 'new_access_log':
                    // 在列表顶部添加新的日志条目，并进行去重
                    setLogs(prevLogs => {
                        // 检查新日志的ID是否已存在于当前列表中
                        const isDuplicate = prevLogs.some(log => log.id === data.payload.id);
                        if (isDuplicate) {
                            // 如果是重复的，则不更新状态，直接返回旧的日志列表
                            console.warn(`WebSocket: Duplicate log received with ID: ${data.payload.id}. Ignoring.`);
                            return prevLogs;
                        }
                        // 如果不是重复的，则添加到列表顶部
                        return [data.payload, ...prevLogs].slice(0, 100); // 只保留最近100条
                    });
                    break;
                case 'error':
                    messageApi.error(`服务器错误: ${data.message}`);
                    break;
                default:
                    console.warn("WebSocket: Received unknown message type:", data.type);
            }
        };

        socket.onclose = (event) => {
            console.log("WebSocket: Connection closed.", event);
            setIsConnected(false);
            if (event.code !== 1000) { // 1000是正常关闭
                setError(`WebSocket disconnected with code: ${event.code}. Reconnecting...`);
                // 实现重连机制
                setTimeout(connect, 5000);
            }
        };

        socket.onerror = (err) => {
            console.error("WebSocket: Error occurred:", err);
            setError("An error occurred with the WebSocket connection.");
            socket.close();
        };

    }, [messageApi]);

    useEffect(() => {
        connect();
        return () => {
            if (socketRef.current) {
                console.log("WebSocket: Closing connection on component unmount.");
                socketRef.current.close(1000); // 正常关闭
            }
        };
    }, [connect]);

    // Function to remove a log entry by its ID
    const removeLogById = (logId: number) => {
        setLogs(prevLogs => prevLogs.filter(log => log.id !== logId));
    };

    const value = {
        devices,
        logs,
        isConnected,
        error,
        removeLogById,
    };

    return (
        <WebSocketContext.Provider value={value}>
            {children}
        </WebSocketContext.Provider>
    );
};